/////////////////////////////////////////////////////////////
//                      C++ Serialization                  //
//                                                         //
//  copyright:   (c) 2011 CPPS                             //
//  authors:     Hikki-Kun                                 //
//  mail:        glrenderable@gmail.com                    //
//                                                         //
//  This program is made available under the terms of      //
//  the MIT License.                                       //
/////////////////////////////////////////////////////////////
#ifndef XML_DESERIALIZATOR_HPP
#define XML_DESERIALIZATOR_HPP

#include "ISerialization.hpp"
#include "Dispatcher.hpp"

#include <istream>
#include <string>
#include <vector>

namespace Serialization
{
  template <typename T>
  class XMLDeserializer : public IDeserializer<T> {
    //
    //  to be able to call "XMLSerializer.Dispatch"
    //
    friend Dispatcher<XMLDeserializer<T>>;

    //
    //  private data members
    //
  private:  
    //
    //  m_stream holds input stream
    //
    std::istream &m_stream;

    //
    //  Hide the default copy constructor
    //
  private:
    //XMLDeserializer(const XMLDeserializer& inst){}

    //
    //  Formaters
    // 
    ////////////// DEBUG! UNSAFE! SLOW! //////////////
    void ShiftToNext() {
      char symbol = 0;
      do {
        m_stream.get(symbol);
      } while (symbol != '>');
    }

    ////////////// DEBUG! UNSAFE! SLOW! //////////////
    bool IsNextTag(const std::string &tag) {
      char symbol = 0;
      do {
        m_stream.get(symbol);
      } while (symbol != '<');

      size_t i = 0;
      m_stream.get(symbol);
      while (symbol != '>') {
        if (tag[i++] != symbol)
          return false;
        m_stream.get(symbol);
      } 
      return true;
    }

    template <typename T>
    void GetContent(T &content) {
      ShiftToNext();
      m_stream >> content;
      ShiftToNext();
    }

    ////////////// DEBUG! UNSAFE! SLOW! //////////////
    template <>
    void GetContent(std::string &content) {
      ShiftToNext();

      char symbol = 0;
      m_stream >> symbol;

      while (symbol != '<') {
        content += symbol;
        m_stream >> symbol;      
      }

      ShiftToNext();
    }

    //
    //  Serialization of a complex type leads to 
    //  instantiation of the nested own template 
    //
  private:
    template <typename T>
    void Deserializate(T &value, const std::string &name) {
      ShiftToNext();

      XMLDeserializer<T> deser(m_stream);
      value.__DESERIALIZE__META__(deser);
     
      ShiftToNext();
    }
    
    //
    //  Deserialization of vector
    //
    template <typename T>
    void Deserializate(std::vector<T> &vec, const std::string &name) {
      ShiftToNext();
     
      int count = 0;
      Deserializate<int>(count, "");
      const size_t length = count;

      for(size_t i = 0; i < length; i++) {
        T item;
        Deserializate(item, "Item");
        vec.push_back(item);
      }

      ShiftToNext();
    }

    //
    //  Deserialization of atom types
    //
  private:
    template <>
    void Deserializate(std::string &value, const std::string &name) {
      GetContent(value);
    }

    template <>
    void Deserializate(int &value, const std::string &name) {
      GetContent(value);
    }

    template <>
    void Deserializate(float &value, const std::string &name) {
      GetContent(value);
    }

    template <>
    void Deserializate(double &value, const std::string &name) {
      GetContent(value);
    }

    //
    //  Used by Dispatcher for flushing arguments
    //
    template <typename T>
    void Dispatch(T &value, const std::string &name) {
      Deserializate(value, name);
    }

    // 
    //  public constructors
    //  
  public:
    XMLDeserializer(std::istream &stream) : 
        m_stream(stream) {
      
    }

    //
    //  IDeserializer interface implementation
    //
  public:
    const IDeserializer& operator>>(T &value) {
      value.__DESERIALIZE__META__(*this);
      return *this;
    }
  };
}

#endif